按照 ECMA-262 标准规定:每一个类都有一个 prototype 属性标识类的原型对象。该属性是静态属性,它有两个作用:实现继承和分享属性。实现继承和分享属性都是原型链的组成。
一、 原型链
原型 实际上就是一个数据集合,即普通对象。继承于 Object 类,由于 JavaScript 自动创建并依附于每一个构造函数。
在原型对象上定义了一些内部属性用于描述该类,其中就包含该类的基类的信息。通过该信息, JavaScript 解释引擎就可以知道该类的基类。同时基类也有相同的构成,因此 JavaScript 解释引擎就可以知道基类的基类,这就建立起了一个链条,因为描述基类信息的内部属性称为 [Prototype] ,所以,该链条也被称为原型链( prototype chain )。
__proto__ 和 prototype 属性的区别
prototype 属性是一个静态属性, __proto__ 属性则是一个实例属性。 prototype 属性表示类的原型对象, __proto__ 属性表示原型对象中定义的内部属性 [Prototype] 的值。
IE 不支持使用 __proto__ 属性,其他几个主流浏览器都支持该属性。
注意的点
- 原型链的顶端都是
null:所有的原型链最终都将指向null,它是原型链的终点; - 每一个函数都有一个
prototype属性:只有非箭头函数的函数才有prototype属性,这个属性是一个对象,当使用new操作符创建实例时,实例的内部会指向这个prototype对象; - 实例 [Prototype] 指向构造函数的
prototype:于上面同理; - 修改原型将影响所有的实例:如果原型上添加或修改了属性,那么已有的所有的和未来的实例都将受到影响;
- 属性屏蔽:实例自身的属性如果与原型链上的某属性同名,将在访问时返回实例自身的属性。但是,原型上同名属性依旧存在,只是在该实例的使用时被屏蔽了。可以通过
delete操作符删除这个自身的属性,从而访问原型链上的属性; - 新能问题:过长的原型链长度将影响性能,每一次查找都将遍历整个链;
- 构建:使用
Object.create(null)创建纯粹的对象,这样创建的对象没有原型(即 [prototype] 指向null),不会继承任何Object.prototype上的方法,适用于纯粹字典对象的场景
二、 判定属性
使用 hasOwnProperty 和 in 可判断一个属性是否存在于原型链或实例自身:
三、封装
当其他部分的代码想要执行对象的某些操作时,可以借助对象向外提供的接口完成操作,借此,对象保持了自身的内部状态不会被外部代码随意修改。对象的内部保持了私有性,而外部代码只能通过对象所提供的接口访问和修改对象的内部状态,不能直接访问和修改对象的内部状态。
保持对象内部状态的私有性、明确划分对象的公共接口和内部状态,这些特性称之为封装(encapsulation)。